#include <iostream>
#include <string>
#include <memory>
using namespace std;

/******************************
 *  简单工厂 Simple Factory 
 *    优点：把对象的创建封装在一个接口函数里面，通过传入不同的标识参数，返回创建的对象
 *        客户不用自己关注new对象，不用了解对象创建的详细过程
 *    不足：提供创建对象实例的接口函数不闭合，不能对修改关闭
 *
 *  工厂方法 Factory Method
 *    优点：Factory基类，提供了一个纯虚函数(创建产品)，定义派生类(具体产品的工厂)负责创建对应的产品，
 *        可以做到不同的产品，在不同的工厂里面创建，能够对现有工厂，以及产品的修改关闭，模块化清晰。
 *    不足：实际上，很多产品是有关联关系的，属于一个产品簇，不应该放在不同的工厂里面去创建，
 *        这样一是不符合实际的产品对象创建逻辑，二是工厂类太多了，不好维护
 * 
 *  抽象工厂 Abstract Factory
 * 
 *  工厂模式：封装对象的创建
 *    优点：把有关联关系的、属于一个产品簇的所有产品创建的接口函数，放在一个抽象工厂 AbstractFactory 里面 
 *        派生类(具体产品的工厂) 负责创建该产品簇里面所有的产品
 */

// 系列产品1
class Car
{
public:
    Car(string name) : _name(name) {}
    virtual void show() = 0;
protected:
    string _name;
};

class BMW : public Car
{
public:
    BMW(string name) : Car(name) {}
    void show()
    {
        cout << "get a BMW object: " << _name << '\n';
    }
};

class Audi : public Car
{
public:
    Audi(string name) : Car(name) {}
    void show()
    {
        cout << "get a Audi object: " << _name << '\n';
    }
};

// 系列产品2
class Light
{
public:
    virtual void show() = 0;
};

class BMWLight : public Light
{
public:
    void show() { cout << "get a BMW light\n"; }
};

class AudiLight : public Light
{
public:
    void show() { cout << "get a Audi light\n"; }
};


// 简单工厂
#if 0   
enum class CarType
{
    BMW,
    AUDI
};

class SimpleFactory
{
public:
    // 工厂设计不封闭，增删都需要修改接口实现
    Car* createCar(CarType ct)     
    {
        switch (ct)
        {
        case CarType::BMW:
            return new BMW("x5");
        case CarType::AUDI:
            return new BMW("A6");
        default:
            cerr << "传入的工厂参数不正确\n"; 
            break;
        }
        return nullptr;
    }
};

int main()
{
    // 需要自己创建对象
    // Car* p1 = new BMW("x5");
    // Car* p2 = new BMW("A6");

    // 不需要关心如何创建对象
    unique_ptr<SimpleFactory> factory(new SimpleFactory());
    unique_ptr<Car> p1(factory->createCar(CarType::BMW));
    unique_ptr<Car> p2(factory->createCar(CarType::AUDI));
    p1->show();
    p2->show();

    // 简单工厂不合理，同一个工厂创建不同的汽车对象

    return 0;
}
#endif


#if 0
class Factory
{
public:
    virtual Car* createCar(const string& name) = 0;
};

class BWMFactory : public Factory
{
public:
    Car* createCar(const string& name)
    {
        return new BMW(name);
    }
};

class AudiFactory : public Factory
{
public:
    Car* createCar(const string& name)
    {
        return new Audi(name);
    }
};

int main()
{
    // 不同品牌产品使用不同的工厂，
    // 但每个品牌可能有多类产品，每个产品都需要一个工厂，这样会导致工厂类过多
    unique_ptr<Factory> BMWfactory(new BWMFactory());
    unique_ptr<Factory> Audifactory(new AudiFactory());
    unique_ptr<Car> p1(BMWfactory->createCar("x5"));
    unique_ptr<Car> p2(Audifactory->createCar("A8"));
    p1->show();
    p2->show();
    return 0;
}
#endif


// 工厂方法 --> 抽象工厂(对有一组关联关系的产品簇提供产品对象的统一创建)
class AbstractFactory
{
public:
    virtual Car* createCar(const string& name) = 0;  // 工厂方法，创建汽车
    virtual Light* createLight() = 0;   // 工厂方法，创建汽车关联产品车灯
};

class BWMFactory : public AbstractFactory
{
public:
    Car* createCar(const string& name){ return new BMW(name); }
    Light* createLight() { return new BMWLight(); }
};

class AudiFactory : public AbstractFactory
{
public:
    Car* createCar(const string& name) { return new Audi(name); }
    Light* createLight() { return new AudiLight(); }
};

int main()
{
    // 抽象工厂，一组具有关联的产品创建统一的对象
    unique_ptr<AbstractFactory> BMWfactory(new BWMFactory());
    unique_ptr<AbstractFactory> Audifactory(new AudiFactory());
    unique_ptr<Car> p1(BMWfactory->createCar("x5"));
    unique_ptr<Car> p2(Audifactory->createCar("A8"));
    unique_ptr<Light> l1(BMWfactory->createLight());
    unique_ptr<Light> l2(Audifactory->createLight());
    p1->show();
    l1->show();
    p2->show();
    l2->show();
    return 0;
}